﻿using System;
using System.Collections.Generic;
using System.Text;
using AGHFiraPlayer.Strategies.StrategiesImpl;
using AGHFiraPlayer.Exceptions;
using System.Reflection;

namespace AGHFiraPlayer.Strategies
{
    public abstract class StrategiesManager
    {
        //here will be held all implmeneted strategies including their availability which can be changed from gui's checklistbox
        private static Dictionary<Type, StrategyPool> strategyPools = new Dictionary<Type, StrategyPool>();
        private static Boolean initCalled = false;
        private static IStrategy strategy;
        private static List<IStrategy> strategies = new List<IStrategy>();
        private static List<Type> strategiesTypes = new List<Type>();

        // here all available strategies will be registered
        public static void init(AGHDriver driver)
        {
            StrategiesManager.initCalled = true;

            strategyPools.Add(typeof(BasicGoalKeeperStrategy), new StrategyPool(typeof(BasicGoalKeeperStrategy), driver));
            strategyPools.Add(typeof(OffensiveSweeperStrategy), new StrategyPool(typeof(OffensiveSweeperStrategy), driver));
            //strategiesPermissions.Add(typeof(TestAttackerStrategy), new StrategyPool(typeof(TestAttackerStrategy), driver));
            //strategiesPermissions.Add(typeof(DeffensiveSweeperStrategy), new StrategyPool(typeof(DeffensiveSweeperStrategy), driver));
            strategyPools.Add(typeof(SimpleShotStrategy), new StrategyPool(typeof(SimpleShotStrategy), driver));
            //strategiesPermissions.Add(typeof(BasicOffensiveStrategy), new StrategyPool(typeof(BasicOffensiveStrategy), driver));
            strategyPools.Add(typeof(SimplePassStrategy), new StrategyPool(typeof(SimplePassStrategy), driver));
          //  strategyPools.Add(typeof(TwoRobotPassStrategy), new StrategyPool(typeof(TwoRobotPassStrategy), driver));
        }
        public static void permitStrategy(Type strategy) 
        {
            if (!StrategiesManager.initCalled)
                throw new StrategiesFactoryInitializationException("Init method has to be called before using any StrategiesFactory class methods");

            strategyPools[strategy].permit();
        }

        public static void permitOneOnlyStrategy(Type strategy)
        {
            if (!StrategiesManager.initCalled)
                throw new StrategiesFactoryInitializationException("Init method has to be called before using any StrategiesFactory class methods");

            foreach (Type strat in strategyPools.Keys)
            {
                strategyPools[strat].forbid();
            }

            strategyPools[strategy].permit();
        }

        public static void forbidStrategy(Type strategy)
        {
            if (!StrategiesManager.initCalled)
                throw new StrategiesFactoryInitializationException("Init method has to be called before using any StrategiesFactory class methods");

            strategyPools[strategy].forbid();
        }

        internal static List<IStrategy> getAllStrategies()
        {
            if (!StrategiesManager.initCalled)
                throw new StrategiesFactoryInitializationException("Init method has to be called before using any StrategiesFactory class methods");

            strategies.Clear();
            foreach (StrategyPool pool in strategyPools.Values) {
                strategy = pool.getFromPool();
                if (strategy != null)
                    strategies.Add(strategy);
            }

            return strategies;
        }

        internal static List<IStrategy> getAllowedStrategies()
        {
            if (!StrategiesManager.initCalled)
                throw new StrategiesFactoryInitializationException("Init method has to be called before using any StrategiesFactory class methods");

            strategies.Clear();
            foreach (StrategyPool pool in strategyPools.Values) {
                strategy = pool.getFromPoolIfAllowed();
                if (strategy != null)
                    strategies.Add(strategy);
            }

            return strategies;
        }

        internal static List<Type> getAllStrategiesTypes()
        {
            if (!StrategiesManager.initCalled)
                throw new StrategiesFactoryInitializationException("Init method has to be called before using any StrategiesFactory class methods");

            strategiesTypes.Clear();
            foreach (Type strategyType in strategyPools.Keys)
            {
                strategiesTypes.Add(strategyType);
            }

            return strategiesTypes;
        }

        internal static void returnToPool(List<IStrategy> strategies)
        {
            foreach (IStrategy strategy in strategies) {
                strategyPools[strategy.GetType()].returnToPool(strategy);
            }
        }
    }
}